/*
 * Copyright (C) 2012 Jonathan St-Michel <jonathan@abiwebz.net>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package org.abiwebz.platform;

import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Enumeration;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JOptionPane;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.abiwebz.platform.util.ErrorHandling;
import org.abiwebz.platform.util.ModuleLoader;
import org.abiwebz.platform.util.icons.Theme;
import org.abiwebz.platform.view.IView;
import org.abiwebz.platform.window.ApplicationWindow;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

/**
 *
 * @author stmicj
 */
public abstract class ApplicationPlugin extends Plugin {

    private static final String CONFIG_FILE = "config.xml";
    
    protected ApplicationWindow mainWindow;
    
    public abstract IView configureView();

    /**
     * Permet de quitter l'application à partir de n'importe où. Cette fonction 
     * devrait être la seule qui permet de quitter pour éviter de perdre des 
     * instructions importantes.
     */
    public void exit() {
        //TODO La fonction des erreurs et des messages (langues) sera changée
        if (ErrorHandling.getInstance().confirm("0xA02", "platform") == JOptionPane.YES_OPTION) {
            System.exit(0);
        }
    }

    /**
     * Retourner la fenêtre principale de l'application. Si elle n'est pas créée
     * elle le sera immédiatement.
     * @return La fenêtre principale de l'application
     */
    public ApplicationWindow getWindow() {
        if (this.mainWindow == null) {
            this.mainWindow = new ApplicationWindow();
        }
        return this.mainWindow;
    }

    /**
     * Fonction générale de configuration pour tous les plugins. La fonction 
     * recherche les fichiers "config.xml" qui sont présent dans le ModuleLoader
     * et ensuite configure les différentes fonctionnalités de la platforme avec
     * le contenu de ces fichiers.
     */
    public void configure() {
        try {
            Enumeration<URL> resources = ModuleLoader.getInstance().getResources(CONFIG_FILE);
            InputStream is;
            while (resources.hasMoreElements()) {
                is = resources.nextElement().openStream();
                Element e = retrieveXML(is);
                
                Theme.buildFromXml(e);
                configureApplication(e);
                getWindow().getRibbonManager().buildFromXml(e);
                
                is.close();
            }
        } catch (IOException ex) {
            Logger.getLogger(Plugin.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    /**
     * Permet de créé l'élement racine du fichier xml "is". Une fois le document
     * chargé il peut être utilisé plusieurs fois.
     * @param is Le fichier xml en InputStream
     * @return Un Element racine du fichier XML
     */
    private Element retrieveXML(InputStream is) {
        try {
            DocumentBuilder docBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
            Document doc = docBuilder.parse(is);
            doc.getDocumentElement().normalize();
            return doc.getDocumentElement();
        } catch (IOException ex) {
            Logger.getLogger(ApplicationPlugin.class.getName()).log(Level.SEVERE, null, ex);
        } catch (ParserConfigurationException ex) {
            Logger.getLogger(ApplicationPlugin.class.getName()).log(Level.SEVERE, null, ex);
        } catch (SAXException ex) {
            Logger.getLogger(ApplicationPlugin.class.getName()).log(Level.SEVERE, null, ex);
        }
        return null;
    }

    /**
     * Permet de configurer l'application selon le tag xml "application".
     * @param root Élément racine du xml
     */
    private void configureApplication(Element root) {
        Node node;
        Element e;
        
        NodeList ribbonList = root.getElementsByTagName("application");
        for (int rid = 0; rid < ribbonList.getLength(); rid++) {
            node = ribbonList.item(rid);
            if (node.getNodeType() == Node.ELEMENT_NODE) {
                e = ((Element) node);
                //Set look & Feel
                String laf = e.getAttribute("laf");
                if(laf != null){
                    if(!laf.equals("")){
                        try {
                            try {
                                UIManager.setLookAndFeel(laf);
                            } catch (InstantiationException ex) {
                                Logger.getLogger(ApplicationPlugin.class.getName()).log(Level.SEVERE, null, ex);
                            } catch (IllegalAccessException ex) {
                                Logger.getLogger(ApplicationPlugin.class.getName()).log(Level.SEVERE, null, ex);
                            } catch (UnsupportedLookAndFeelException ex) {
                                Logger.getLogger(ApplicationPlugin.class.getName()).log(Level.SEVERE, null, ex);
                            }
                        } catch (ClassNotFoundException ex) {
                            Logger.getLogger(ApplicationPlugin.class.getName()).log(Level.SEVERE, null, ex);
                        }
                    }
                }
                
                getWindow().setTitle(e.getAttribute("title"));
                getWindow().setApplicationIcon(Theme.getInstance(Application.theme).getIconAsResizable(e.getAttribute("icon")));
            }
        }
    }
}
